import path from 'path'
import fs from 'fs'
import { hash256, fileHash as getFileHash } from '@/utils/tools'
import db from './db'
import request from '@/utils/request'
const chunkSize = 3 * 1024 * 1024     //每片分块的大小3M

export default {
    files:{}, // {updateCallback: func, uploading: boolean, path: string,
    allFiles:[], // 只存hash
    uploadingCount: 0,
    /**
     * 上传文件流程
     * 1.得到hash值
     * 2.获取上传记录
     * 3.数据切块
     * 4.上传数据
     * 5.记录进度
     * 6.重复步骤3
     */
    send(filePath, uploadPath, updateCallback) {
        try {
            console.log(filePath)
            // 1.获得hash
            const fileHash = hash256(filePath)
            this.files[fileHash] = {
                updateCallback : updateCallback,
                uploading: true,
                path: filePath,
                uploadPath: uploadPath
            }
            this.allFiles.push(fileHash)
            this.loopSend()
        } catch (e) {
            console.log(e)
        }
    },
    // 循环发送
    async loopSend() {

        // 正在上传5个 或则 已经上传完毕
        console.log('正在上传数量:' + this.uploadingCount)
        console.log('总数:' + this.allFiles.length)

        if (this.uploadingCount > 2 || this.allFiles.length === 0) {
            return
        }
        const fileHash = this.allFiles[0]
        const filePath = this.files[fileHash].path
        this.allFiles.splice(0,1)
        this.uploadingCount += 1

        // 2.获取上传进度
        const uploadLog = await this.getProgress(fileHash)
        let uploadSize = 1
        if (uploadLog === false) {
            this.initProgress(fileHash, filePath)
        } else {
            uploadSize = uploadLog.upload + 1
        }
        this.singleUpload(filePath, fileHash, uploadSize)
    },
    // 取消上传
    cancel(filePath) {
        const fileHash = getFileHash(filePath)
        this.files[fileHash].uploading = false
        this.allFiles.splice(this.allFiles.indexOf(fileHash), 1)
        // 如果是正在上传的，要将总数减去
    },
    // 获得上传进度
    getProgress(fileHash) {
        return new Promise((resolve, reject) => {
            const sql = `SELECT * FROM files WHERE hash = '${fileHash}' `
            db.db.get(sql, (err, result) => {
                if (result === undefined) {
                    resolve(false)
                } else {
                    resolve(result)
                }
            })
        })
    },
    // 初始化上传进度
    initProgress(path) {
        const fileInfo = fs.statSync(path)
        const size = fileInfo.size
        const total = Math.ceil(size / chunkSize)
        const hash = hash256(path)
        const sql = `INSERT INTO files (path, hash, total, upload, note) VALUES ('${path}', '${hash}', ${total}, 0, '')`
        db.db.run(sql)
    },
    // 更新上传进度
    updateProgress(hash, progress) {
        const sql = `UPDATE files SET upload = ${progress} WHERE hash = '${hash}'`
        db.db.run(sql)
    },
    // 单文件上传
    singleUpload(filePath, fileHash, i) {
        const stats = fs.statSync(filePath)   //读取文件信息
        const extName = path.extname(filePath)
        const size = stats.size           //文件大小
        const chunks = Math.ceil(size / chunkSize)    //总共的分片数
        this.uploadAction(filePath,extName, fileHash, size, i, chunks)
    },
    // 上传动作
    uploadAction(filePath, extName, fileHash, size, i, chunks) {
        // 检查是否已经取消上传
        if (this.files[fileHash].uploading === false) {
            delete this.files[fileHash]
            return
        }
        //计算每块的结束位置
        const content = []
        const end   = Math.min(size, i  * chunkSize)
        const start = (i - 1) * chunkSize
        if (start > size) {
            return this.uploadAction(filePath, extName, fileHash, size, 1, chunks) // 如果传乱了， 从头开始
        }
        //创建一个readStream对象，根据文件起始位置和结束位置读取固定的分片
        const readStream = fs.createReadStream(filePath, {start: start, end: end - 1})

        //on data读取数据
        readStream.on('data', (data) => {
            content.push(data)
        })

        //on end在该分片读取完成时触发
        readStream.on('end', () => {
            //这里服务端只接受blob对象，需要把原始的数据流转成blob对象，这块为了配合后端才转
            let blob = new Blob(content)
            let md5Val = hash256(Buffer.concat(content))

            //新建formdata数据对象
            let formdata = new FormData()
            formdata.append("file", blob)
            formdata.append("md5", md5Val)
            formdata.append("chunk", i + '')        //第几个分片，从0开始
            formdata.append('name', fileHash)
            let config = {headers: {"Content-Type": 'multipart/form-data'}}

            request.post('file/upload', formdata, config).then(res => {
                // 缓存进度
                this.updateProgress(fileHash, i)
                const file = this.files[fileHash]
                file.updateCallback( parseInt(i  / chunks * 100 ))

                if (i < chunks) {

                    setTimeout(()=>{
                        this.uploadAction(filePath, extName, fileHash, size, i + 1, chunks)
                    },1000)

                } else {
                    this.uploadingCount -= 1
                    this.uploadFinish(chunks, fileHash, extName, file.uploadPath)
                    delete this.files[fileHash]
                    this.loopSend()
                }
            }).catch(err => {
                setTimeout(()=>{
                    this.uploadAction(filePath, extName, fileHash, size, i , chunks)
                },1000)

            })
        })
    },
    uploadFinish(chunks, name, ext, uploadPath) {
        this.getProgress(name).then(file => {
            const data = {
                chunks,
                name,
                ext,
                note: file.note,
                title: file.path,
                uploadPath
            }
            request.post('file/merge', data).then(() => {
                // 上传结束
            })
        })
    },
    setNote(path, note) {
        const pathHash = hash256(path)
        const sql = `UPDATE files SET note = '${note}' WHERE hash = '${pathHash}'`
        db.db.run(sql)
        this.getProgress(pathHash).then(file => {
            if (file.upload === file.total) {
                // 请求服务器修改备注
                const name = getFileHash(path)
                request.post('file/update', {name, note}).then(() => {
                  // 修改成功
                })
            }
        }).catch(() => {})
    }
}
